package com.fourtwenty.hemptress;

import java.io.File;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jibble.pircbot.PircBot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fourtwenty.hemptress.plugin.PluginEvent;
import com.fourtwenty.hemptress.plugin.PluginLoader;
import com.fourtwenty.hemptress.plugin.PluginLoadingException;

public class PluginEventBot extends PircBot {
	private static final Logger LOG = LoggerFactory.getLogger(PluginEventBot.class);
	
	private PluginLoader loader = new PluginLoader(new File(System.getProperty("hemptress.plugin.dir", "build/plugin")));
	private EnumMap<PluginEvent, List<BotEventListener>> listeners = new EnumMap<>(PluginEvent.class); 
	
	public void init() {
		try {
			loader.loadPlugins(this);
		} catch (PluginLoadingException e) {
			LOG.error("Error loading plugins", e);
		}
		
		for(PluginEvent be : PluginEvent.values()) {
			addEventListener(be, new PluginEventListener(be));
		}
	}
	
	protected void triggerEvent(PluginEvent e, Map<String, String> params) {
		params.put("reply", findReply(params));
		
		for(BotEventListener bel : listeners.get(e)) {
			bel.trigger(params, this);
		}
	}
	
	private String findReply(Map<String, String> params) {
		//channel message
		if(params.containsKey("channel")) {
			return params.get("channel");
		}
		
		if(params.containsKey("target")) {
			String target = params.get("target");
			if(target.equalsIgnoreCase(this.getNick())) {
				return params.get("sendernick");
			} else {
				return target;
			}
		}
		
		return params.get("sendernick");
	}
	
	public void addEventListener(PluginEvent e, BotEventListener bel) {
		List<BotEventListener> list = listeners.get(e);
		if(list == null) {
			listeners.put(e, new ArrayList<BotEventListener>());
		}
		
		listeners.get(e).add(bel);
	}

	@Override
	protected void onMessage(String channel, String sender, String login, String hostname, String message) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", sender);
		params.put("senderlogin", login);
		params.put("senderhostname", hostname);
		params.put("message", message);
		triggerEvent(PluginEvent.CHANNEL_MESSAGE, params);
	}

	@Override
	protected void onAction(String sender, String login, String hostname, String target, String action) {
		Map<String, String> params = new HashMap<>();
		params.put("target", target);
		params.put("sendernick", sender);
		params.put("senderlogin", login);
		params.put("senderhostname", hostname);
		params.put("action", action);
		triggerEvent(PluginEvent.ACTION, params);
	}
	
	@Override
	protected void onPrivateMessage(String sender, String login, String hostname, String message) {
		Map<String, String> params = new HashMap<>();
		params.put("message", message);
		params.put("sendernick", sender);
		params.put("senderlogin", login);
		params.put("senderhostname", hostname);
		triggerEvent(PluginEvent.ACTION, params);
	}
	
	@Override
	protected void onJoin(String channel, String sender, String login, String hostname) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", sender);
		params.put("senderlogin", login);
		params.put("senderhostname", hostname);
		triggerEvent(PluginEvent.JOIN, params);
	}

	@Override
	protected void onNickChange(String oldNick, String login, String hostname, String newNick) {
		Map<String, String> params = new HashMap<>();
		params.put("oldnick", oldNick);
		params.put("newnick", newNick);
		params.put("senderlogin", login);
		params.put("senderhostname", hostname);
		triggerEvent(PluginEvent.NICK_CHANGE, params);
	}

	@Override
	protected void onPart(String channel, String sender, String login, String hostname) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", sender);
		params.put("senderlogin", login);
		params.put("senderhostname", hostname);
		triggerEvent(PluginEvent.PART, params);
	}

	@Override
	protected void onOp(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", sourceNick);
		params.put("senderlogin", sourceLogin);
		params.put("senderhostname", sourceHostname);
		params.put("target", recipient);
		triggerEvent(PluginEvent.OP, params);
	}

	@Override
	protected void onInvite(String targetNick, String sourceNick, String sourceLogin, String sourceHostname, String channel) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", sourceNick);
		params.put("senderlogin", sourceLogin);
		params.put("senderhostname", sourceHostname);
		params.put("target", targetNick);
		triggerEvent(PluginEvent.INVITE, params);
	}

	@Override
	protected void onDeop(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", sourceNick);
		params.put("senderlogin", sourceLogin);
		params.put("senderhostname", sourceHostname);
		params.put("target", recipient);
		triggerEvent(PluginEvent.DEOP, params);
	}

	@Override
	protected void onVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", sourceNick);
		params.put("senderlogin", sourceLogin);
		params.put("senderhostname", sourceHostname);
		params.put("target", recipient);
		triggerEvent(PluginEvent.VOICE, params);
	}

	@Override
	protected void onDeVoice(String channel, String sourceNick, String sourceLogin, String sourceHostname, String recipient) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", sourceNick);
		params.put("senderlogin", sourceLogin);
		params.put("senderhostname", sourceHostname);
		params.put("target", recipient);
		triggerEvent(PluginEvent.DEVOICE, params);
	}
	
	@Override
	protected void onKick(String channel, String kickerNick, String kickerLogin, String kickerHostname, String recipientNick, String reason) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", kickerNick);
		params.put("senderlogin", kickerLogin);
		params.put("senderhostname", kickerHostname);
		params.put("target", recipientNick);
		params.put("message", reason);
		triggerEvent(PluginEvent.KICK, params);
	}

	@Override
	protected void onTopic(String channel, String topic, String setBy, long date, boolean changed) {
		Map<String, String> params = new HashMap<>();
		params.put("channel", channel);
		params.put("sendernick", setBy);
		params.put("topic", topic);
		params.put("date", date+"");
		triggerEvent(PluginEvent.TOPIC, params);
	}
	
	@Override
	protected void onQuit(String sourceNick, String sourceLogin, String sourceHostname, String reason) {
		Map<String, String> params = new HashMap<>();
		params.put("sendernick", sourceNick);
		params.put("senderlogin", sourceLogin);
		params.put("senderhostname", sourceHostname);
		params.put("message", reason);
		triggerEvent(PluginEvent.QUIT, params);
	}

	
	@Override
	protected void onConnect() {
		triggerEvent(PluginEvent.CONNECT, new HashMap<String, String>());
	}

	@Override
	protected void onDisconnect() {
		triggerEvent(PluginEvent.DISCONNECT, new HashMap<String, String>());
	}
	
	private static class PluginEventListener implements BotEventListener {
		private PluginEvent e;
		public PluginEventListener(PluginEvent e) {
			this.e = e;
		}
		
		@Override
		public void trigger(Map<String, String> params, PluginEventBot bot) {
			bot.loader.getEvents().triggerEvent(e, params, bot);
		}
	}

	public PluginLoader getLoader() {
		return loader;
	}

	protected void setLoader(PluginLoader loader) {
		this.loader = loader;
	}
}
